package checker

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	_ "github.com/go-sql-driver/mysql"
)

type MySQLChecker struct {
	name    string
	dsn     string
	query   string
	timeout time.Duration
}

func NewMySQLChecker(name, host string, port int, username, password, query string, timeout time.Duration) *MySQLChecker {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/?timeout=%ds",
		username, password, host, port, int(timeout.Seconds()))
	return &MySQLChecker{
		name:    name,
		dsn:     dsn,
		query:   query,
		timeout: timeout,
	}
}

func (c *MySQLChecker) Name() string {
	return c.name
}

func (c *MySQLChecker) Check(ctx context.Context) Result {
	ctx, cancel := context.WithTimeout(ctx, c.timeout)
	defer cancel()

	db, err := sql.Open("mysql", c.dsn)
	if err != nil {
		return Result{
			Name:   c.name,
			OK:     false,
			Error:  err,
			Detail: fmt.Sprintf("mysql open failed: %v", err),
		}
	}
	defer db.Close()

	db.SetConnMaxLifetime(c.timeout)

	if err := db.PingContext(ctx); err != nil {
		return Result{
			Name:   c.name,
			OK:     false,
			Error:  err,
			Detail: fmt.Sprintf("mysql ping failed: %v", err),
		}
	}

	var one int
	err = db.QueryRowContext(ctx, c.query).Scan(&one)
	if err != nil && err != sql.ErrNoRows {
		return Result{
			Name:   c.name,
			OK:     false,
			Error:  err,
			Detail: fmt.Sprintf("mysql query failed: %v", err),
		}
	}

	return Result{
		Name:   c.name,
		OK:     true,
		Detail: "mysql query succeeded",
	}
}
